Skip to content

fix(backend-tests): un-skip api/ and admin/ subdirectory specs#7789

Merged
JohnMcLear merged 2 commits into
developfrom
fix/backend-tests-glob
May 17, 2026
Merged

fix(backend-tests): un-skip api/ and admin/ subdirectory specs#7789
JohnMcLear merged 2 commits into
developfrom
fix/backend-tests-glob

Conversation

@JohnMcLear
Copy link
Copy Markdown
Member

Summary

pnpm test (in src/) has been silently skipping every backend spec under tests/backend/specs/api/ and tests/backend/specs/admin/. The glob tests/backend/specs/**.ts only resolves to files at depth 1 — ** without a slash separator is treated like * by both bash and minimatch, and the shell pre-expands the pattern before mocha sees it, so --recursive has nothing to recurse into.

Confirmed against the most recent green CI run on develop (b96e262, run id 25970235389):

  • No mention of pad.ts, importexportGetPost.ts, listAuthorsOfPad, copyPadWithoutHistory, or any other test name from the api/admin subdirs.
  • No other workflow runs tests/backend/specs/api/** either.

The fix passes the directories to mocha with --extension ts --recursive so mocha does its own walk.

What this surfaces

After the fix, mocha picks up 74 spec files instead of 53. The 16 newly-discovered files contain 6 failing tests:

File Test Filed as
tests/backend/specs/api/pad.ts Get Authors of the Pad #7785
tests/backend/specs/api/pad.ts Pad with complex nested lists of different types #7786
tests/backend/specs/api/pad.ts copyPadWithoutHistory > creates a new pad with the same content as the source pad #7787
tests/backend/specs/api/importexportGetPost.ts txt request rev test1 is 403 #7788
tests/backend/specs/api/importexportGetPost.ts html request rev test1 results in 500 response #7788
tests/backend/specs/api/appendTextAuthor.ts appendText without authorId does not attribute to any author not yet filed — same shape as #7785

All admin/ specs pass.

Two tests listed in #7786's body (ugly HTML, white space between list items) and one in #7787 (attribute pools are independent) do not reproduce as failures on develop HEAD; the issue bodies are slightly stale there.

Trade-off

This change will make the next CI run red until #7785#7788 (and the new appendTextAuthor.ts failure) are fixed. That's the point — those tests have been silently broken. Merging this is what makes them visible.

Test plan

  • Local run on a fresh clone of develop (b96e262) with Node 24.14.0 reproduces the 6 failures listed above.
  • Dry-run with the new glob enumerates 74 spec files (up from 53).
  • CI will turn red on this PR — that's expected; track the 5 follow-up fixes against the issues above.

🤖 Generated with Claude Code

The pnpm test script's glob `tests/backend/specs/**.ts` only matched
files at the top level of tests/backend/specs/. Every spec under
tests/backend/specs/api/ (14 files) and tests/backend/specs/admin/
(2 files) has been silently skipped by CI — including the failing
tests reported in #7785, #7786, #7787, #7788.

Switch to passing the directories with `--extension ts --recursive`,
which makes mocha walk the tree the way --recursive is documented to.

Local run after this change picks up 16 additional spec files and
surfaces 6 newly-visible failures: 4 already filed (#7785#7788) plus
one that wasn't yet filed (appendTextAuthor.ts:
"appendText without authorId does not attribute to any author").

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@qodo-code-review
Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Review Summary by Qodo

Fix backend test glob to discover nested spec directories

🐞 Bug fix 🧪 Tests

Grey Divider

Walkthroughs

Description
• Fix glob pattern to include nested test directories
  - Changed from tests/backend/specs/**.ts to tests/backend/specs with `--extension ts
  --recursive`
  - Mocha now discovers 74 spec files instead of 53 (16 additional files)
• Surfaces 6 previously hidden failing tests in api/ and admin/ subdirectories
  - Tests in pad.ts, importexportGetPost.ts, and appendTextAuthor.ts now visible
• Enables proper recursive test discovery for plugin specs
  - Plugin specs in ../node_modules/ep_*/static/tests/backend/specs also benefit from recursive flag
Diagram
flowchart LR
  A["Old glob pattern<br/>tests/backend/specs/**.ts"] -->|"Only matches<br/>top-level files"| B["53 spec files<br/>discovered"]
  C["New glob pattern<br/>tests/backend/specs<br/>with --recursive"] -->|"Walks directory tree<br/>recursively"| D["74 spec files<br/>discovered"]
  B -->|"Skips"| E["api/ subdirectory<br/>14 files hidden"]
  B -->|"Skips"| F["admin/ subdirectory<br/>2 files hidden"]
  D -->|"Includes"| E
  D -->|"Includes"| F
  E -->|"Surfaces"| G["6 failing tests<br/>now visible"]
Loading

Grey Divider

File Changes

1. src/package.json 🐞 Bug fix +1/-1

Update test script glob for recursive discovery

• Modified test script glob pattern from tests/backend/specs/**.ts to tests/backend/specs
• Added --extension ts --recursive flags to enable mocha's directory tree walking
• Updated plugin spec path from ../node_modules/ep_*/static/tests/backend/specs/** to
 ../node_modules/ep_*/static/tests/backend/specs
• Allows discovery of 16 previously skipped test files in api/ and admin/ subdirectories

src/package.json


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

qodo-free-for-open-source-projects Bot commented May 17, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0)

Context used

Grey Divider


Remediation recommended

1. No regression test for pnpm test 📘 Rule violation ☼ Reliability
Description
This PR fixes a bug where backend specs in nested subdirectories were silently skipped, but it does
not add an automated regression test/check to ensure nested spec discovery cannot silently break
again. Without a regression check, future script or runner changes could reintroduce skipped tests
without detection.
Code

src/package.json[150]

+    "test": "cross-env NODE_ENV=production mocha --import=tsx --require ./tests/backend/diagnostics.ts --timeout 120000 --extension ts --recursive tests/backend/specs ../node_modules/ep_*/static/tests/backend/specs",
Evidence
Compliance ID 7 requires a regression test for bug fixes. The only change in this PR is the test
script update, and there is no accompanying added test or automated verification that pnpm test
still includes nested api/ and admin/ specs if the script is reverted or altered.

src/package.json[148-151]
Best Practice: Repository guidelines

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR fixes backend test discovery by changing the mocha invocation, but there is no automated regression test/check that would fail if nested spec discovery breaks again.

## Issue Context
The bug was that specs under `tests/backend/specs/api/` and `tests/backend/specs/admin/` were silently skipped due to the previous glob. The fix changes `pnpm test` to pass directories with `--extension ts --recursive`, but nothing asserts that mocha still discovers nested specs in future changes.

## Fix Focus Areas
- src/package.json[148-151]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: Linux with Plugins (24)

Failed stage: Run the backend tests [❌]

Failed test name: src/tests/backend/specs/admin/anonymizeAuthorSocket.ts: authorLoad returns paginated rows

Failure summary:

The GitHub Action failed because pnpm test (Mocha) reported multiple failing tests and exited
non-zero (Exit status 13, [ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL], Process completed with exit code 13).

The failures shown in the log are:
- 7 tests in
src/tests/backend/specs/admin/anonymizeAuthorSocket.ts timed out after 120000ms (lines ~4577–4611),
indicating async socket tests never completed / promises never resolved.
- Examples: authorLoad
returns paginated rows, anonymizeAuthorPreview returns counters..., handlers do not crash on
payload-less emits.
- src/tests/backend/specs/api/appendTextAuthor.ts: appendText without authorId
does not attribute to any author failed an assertion at
tests/backend/specs/api/appendTextAuthor.ts:84:12 (expected 0 authors but got 1; lines ~4614–4622).

- src/tests/backend/specs/api/importexportGetPost.ts: two export revision error-path tests failed
because the response body was an HTML Internal Server Error page instead of matching /rev is not a
number/:
- txt request rev test1 is 403 failed at
tests/backend/specs/api/importexportGetPost.ts:622:41 (lines ~4623–4650).
- html request rev test1
results in 500 response failed at tests/backend/specs/api/importexportGetPost.ts:662:41 (lines
~4651–4678).
- The server logged apierror: rev is not a number from checkValidRev
(src/node/utils/checkValidRev.ts:14:11) called by src/node/handler/ExportHandler.ts:64:22 (lines
~2013–2032), but the HTTP response observed by the tests was still a generic 500 HTML error.
-
src/tests/backend/specs/api/pad.ts: three assertion failures:
- Get Authors of the Pad at
tests/backend/specs/api/pad.ts:287:14 (expected 0, got 1; lines ~4679–4688).
- Pad with complex
nested lists of different types at tests/backend/specs/api/pad.ts:490:14 (HTML mismatch: nested

    is
    missing expected start="2"; lines ~4689–4700).
    - copyPadWithoutHistory creates a new pad with the
    same content as the source pad at tests/backend/specs/api/pad.ts:619:14 (same HTML mismatch; lines
    ~4701–4712).

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

178:  [command]/home/runner/setup-pnpm/node_modules/.bin/bin/pnpm store path --silent
179:  /home/runner/setup-pnpm/node_modules/.bin/store/v11
180:  Cache hit for: node-cache-Linux-x64-pnpm-69bce3630d8e140abc2b647fe8bdbbe78750f8d416bc72242c5e9034d8cec9ea
181:  Received 4194304 of 175179674 (2.4%), 4.0 MBs/sec
182:  Received 134217728 of 175179674 (76.6%), 64.0 MBs/sec
183:  Received 175179674 of 175179674 (100.0%), 69.4 MBs/sec
184:  Cache Size: ~167 MB (175179674 B)
185:  [command]/usr/bin/tar -xf /home/runner/work/_temp/54b9fcd2-9b42-4e15-8c15-86eb0432c671/cache.tzst -P -C /home/runner/work/etherpad/etherpad --use-compress-program unzstd
186:  Cache restored successfully
187:  Cache restored from key: node-cache-Linux-x64-pnpm-69bce3630d8e140abc2b647fe8bdbbe78750f8d416bc72242c5e9034d8cec9ea
188:  ##[group]Run awalsh128/cache-apt-pkgs-action@v1.6.0
189:  with:
190:  packages: libreoffice libreoffice-pdfimport
191:  version: 1
192:  execute_install_scripts: false
193:  empty_packages_behavior: error
194:  debug: false
...

201:  �[36;1m  "$VERSION" \�[0m
202:  �[36;1m  "$EXEC_INSTALL_SCRIPTS" \�[0m
203:  �[36;1m  "$DEBUG" \�[0m
204:  �[36;1m  "$ADD_REPOSITORY" \�[0m
205:  �[36;1m  "$PACKAGES"�[0m
206:  �[36;1mif [ -f ~/cache-apt-pkgs/cache_key.md5 ]; then�[0m
207:  �[36;1m  echo "CACHE_KEY=$(cat ~/cache-apt-pkgs/cache_key.md5)" >> $GITHUB_ENV�[0m
208:  �[36;1melse�[0m
209:  �[36;1m  echo "CACHE_KEY=" >> $GITHUB_ENV�[0m
210:  �[36;1mfi�[0m
211:  shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
212:  env:
213:  PNPM_HOME: /home/runner/setup-pnpm/node_modules/.bin
214:  VERSION: 1
215:  EXEC_INSTALL_SCRIPTS: false
216:  EMPTY_PACKAGES_BEHAVIOR: error
217:  DEBUG: false
...

505:  ╭ Warning ─────────────────────────────────────────────────────────────────────╮
506:  │                                                                              │
507:  │   Ignored build scripts: argon2@0.44.0, bcrypt@6.0.0, esbuild@0.28.0.        │
508:  │   Run "pnpm approve-builds" to pick which dependencies should be allowed     │
509:  │   to run scripts.                                                            │
510:  │                                                                              │
511:  ╰──────────────────────────────────────────────────────────────────────────────╯
512:  Done in 9.7s using pnpm v11.1.2
513:  ##[group]Run mkdir -p "/home/runner/work/etherpad/etherpad/node-report"
514:  �[36;1mmkdir -p "/home/runner/work/etherpad/etherpad/node-report"�[0m
515:  �[36;1mpnpm test�[0m
516:  shell: /usr/bin/bash -e {0}
517:  env:
518:  PNPM_HOME: /home/runner/setup-pnpm/node_modules/.bin
519:  CACHE_KEY: 158a**************************da
520:  NODE_OPTIONS: --report-on-fatalerror --report-uncaught-exception --report-on-signal --report-compact --report-directory=/home/runner/work/etherpad/etherpad/node-report
521:  ##[endgroup]
...

590:  ✔ author already exists, no pads
591:  ✔ author already exists, on different pad
592:  ✔ author already exists, on same pad
593:  enforces consistent pad ID
594:  ✔ pad record has different pad ID
595:  ✔ globalAuthor record has different pad ID
596:  ✔ pad rev record has different pad ID
597:  order of records does not matter
598:  ✔ [0,1,2]
599:  ✔ [0,2,1]
600:  ✔ [1,0,2]
601:  ✔ [1,2,0]
602:  ✔ [2,0,1]
603:  ✔ [2,1,0]
604:  old .etherpad imports without author metadata
605:  ✔ imports without error when revision lacks meta.author
606:  ✔ getRevisionAuthor returns empty string for missing author
607:  exportEtherpadAdditionalContent
608:  ✔ imports from custom prefix
609:  ✔ rejects records for pad with similar ID
610:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/LinkInstaller.ts
611:  readFileSync with plain paths (bug fix)
612:  ✔ reads a plugin package.json using a plain file path and utf-8
613:  ✔ path.join produces a plain string path, not a URL object
614:  addSubDependency-style resolution
615:  ✔ recursively resolves nested dependencies from package.json files
616:  error handling when package.json is missing
617:  ✔ logs an error instead of crashing when package.json does not exist
618:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/Pad.ts
...

775:  ✔ does not start until needed
776:  ✔ fewer than buffer size
777:  ✔ exactly buffer size
778:  ✔ more than buffer size
779:  ✔ buffered Promise rejections are suppressed while iterating (100ms)
780:  ✔ buffered Promise rejections are unsuppressed when iteration completes (101ms)
781:  map
782:  ✔ empty
783:  ✔ does not start until needed
784:  ✔ works
785:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/admin/anonymizeAuthorSocket.ts
786:  �[32m[2026-05-17T11:53:13.100] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user guest
787:  1) authorLoad returns paginated rows
788:  2) anonymizeAuthorPreview returns counters without flipping erased
789:  3) anonymizeAuthor commits when the flag is enabled
790:  4) anonymizeAuthor returns {error: "disabled"} when flag is off
791:  5) anonymizeAuthorPreview returns {error: "disabled"} when flag is off
792:  6) authorLoad returns {error: "disabled"} when flag is off
793:  7) handlers do not crash on payload-less emits
794:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/admin/authorSearch.ts
795:  ✔ returns an empty page when the pattern matches nothing
796:  ✔ matches by name substring
797:  ✔ matches by mapper substring (joins mapper2author)
798:  ✔ hides erased authors by default and includes them when asked
799:  ✔ sorts by lastSeen
800:  ✔ caps results at 1000 and reports cappedAt (237ms)
801:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/anonymizeAuthor.ts
802:  ✔ zeroes the display identity on globalAuthor:<id>
803:  ✔ drops token2author and mapper2author mappings pointing at the author
804:  ✔ is idempotent — second call returns zero counters
805:  ✔ returns zero counters for an unknown authorID
806:  ✔ re-runs the sweep when a prior call errored before setting erased=true
807:  ✔ dryRun returns the same counter shape but does not mutate the record
...

817:  truncated mode
818:  ✔ zeros the last octet of v4
819:  ✔ keeps the first /48 of a compressed v6
820:  ✔ keeps the first /48 of a fully written v6
821:  ✔ truncates v4 inside a v4-mapped v6
822:  ✔ returns ANONYMOUS for a non-IP string
823:  empty / null input
824:  ✔ returns ANONYMOUS for null in full mode
825:  ✔ returns ANONYMOUS for '' in full mode
826:  ✔ returns ANONYMOUS for null in truncated mode
827:  ✔ returns ANONYMOUS for '' in truncated mode
828:  ✔ returns ANONYMOUS for null in anonymous mode
829:  ✔ returns ANONYMOUS for '' in anonymous mode
830:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/api/anonymizeAuthor.ts
831:  ✔ anonymizeAuthor zeroes the author and returns counters
832:  ✔ anonymizeAuthor with missing authorID returns an error
833:  ✔ anonymizeAuthor returns an apierror when gdprAuthorErasure is disabled
834:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/api/api.ts
...

843:  ✔ declares a top-level tags array with all expected resource groups
844:  ✔ tags every operation with at least one non-empty tag
845:  ✔ summarizes every operation
846:  ✔ advertises only POST per path (downstream tooling cleanliness)
847:  runtime backward compatibility (GET + POST still routed)
848:  ✔ GET requests still reach the API handler
849:  ✔ POST requests still reach the API handler
850:  ✔ REST-style /rest/<ver>/pad/checkToken still resolves
851:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/api/appendTextAuthor.ts
852:  ✔ appendText with authorId attributes the text to that author
853:  8) appendText without authorId does not attribute to any author
854:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/api/characterEncoding.ts
855:  Sanity checks
856:  ✔ can connect
857:  ✔ finds the version tag
858:  ✔ errors with invalid OAuth token
859:  ✔ errors with unprivileged OAuth token
860:  Tests
...

913:  at <anonymous> (/home/runner/work/etherpad/etherpad/src/static/js/pluginfw/hooks.ts:273:18)
914:  at new Promise (<anonymous>)
915:  at callHookFnAsync (/home/runner/work/etherpad/etherpad/src/static/js/pluginfw/hooks.ts:236:16)
916:  at <anonymous> (/home/runner/work/etherpad/etherpad/src/static/js/pluginfw/hooks.ts:351:54)
917:  at Array.map (<anonymous>)
918:  at Object.exports.aCallAll (/home/runner/work/etherpad/etherpad/src/static/js/pluginfw/hooks.ts:351:13)
919:  at getHTMLFromAtext (/home/runner/work/etherpad/etherpad/src/node/utils/ExportHtml.ts:504:19)
920:  at async Object.getPadHTML (/home/runner/work/etherpad/etherpad/src/node/utils/ExportHtml.ts:43:10)
921:  at async Object.exports.getHTML (/home/runner/work/etherpad/etherpad/src/node/db/API.ts:291:14)
922:  at async handler (/home/runner/work/etherpad/etherpad/src/node/hooks/express/openapi.ts:768:20)
923:  at async OpenAPIBackend.handleRequest (/home/runner/work/etherpad/etherpad/node_modules/.pnpm/openapi-backend@5.16.1/node_modules/openapi-backend/src/backend.ts:313:27)
924:  at async <anonymous> (/home/runner/work/etherpad/etherpad/src/node/hooks/express/openapi.ts:814:22)
925:  ✔ get the HTML of Pad with emojis
926:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/api/chat.ts
927:  API Versioning
928:  ✔ errors if can not connect
929:  Chat functionality
...

1404:  - Tries to import .docx that uses soffice
1405:  - exports DOC from imported DOCX
1406:  - exports DOCX from imported DOCX
1407:  - Tries to import .pdf that uses soffice
1408:  - exports PDF
1409:  - Tries to import .odt that uses soffice
1410:  - exports ODT
1411:  malformed .etherpad files are rejected
1412:  �[32m[2026-05-17T12:07:15.647] [INFO] settings - �[39m<ref *2> Response {
1413:  _events: [Object: null prototype] {},
1414:  _eventsCount: 0,
1415:  _maxListeners: undefined,
1416:  res: <ref *1> IncomingMessage {
1417:  _events: {
1418:  close: [Function: bound emit],
1419:  error: [Array],
1420:  data: [Array],
...

1423:  },
1424:  _readableState: ReadableState {
1425:  highWaterMark: 65536,
1426:  buffer: [],
1427:  bufferIndex: 0,
1428:  length: 0,
1429:  pipes: [],
1430:  awaitDrainWriters: null,
1431:  Symbol(kState): 201070460,
1432:  Symbol(kDecoderValue): [StringDecoder],
1433:  Symbol(kEncodingValue): 'utf8'
1434:  },
1435:  _maxListeners: undefined,
1436:  socket: Socket {
1437:  connecting: false,
1438:  _hadError: false,
1439:  _parent: null,
1440:  _host: 'localhost',
1441:  _closeAfterHandlingError: false,
1442:  _events: [Object],
...

1495:  'ETag',
1496:  'W/"3e-c22+Nq37KkPTgt2Yh0qQIIkF+C0"',
1497:  'Connection',
1498:  'close'
1499:  ],
1500:  rawTrailers: [],
1501:  joinDuplicateHeaders: undefined,
1502:  aborted: false,
1503:  upgrade: false,
1504:  url: '',
1505:  method: null,
1506:  statusCode: 200,
1507:  statusMessage: 'OK',
1508:  client: Socket {
1509:  connecting: false,
1510:  _hadError: false,
1511:  _parent: null,
1512:  _host: 'localhost',
1513:  _closeAfterHandlingError: false,
1514:  _events: [Object],
...

1590:  upgradeOrConnect: false,
1591:  parser: null,
1592:  maxHeadersCount: null,
1593:  reusedSocket: false,
1594:  host: 'localhost',
1595:  protocol: 'http:',
1596:  Symbol(shapeMode): false,
1597:  Symbol(kCapture): false,
1598:  Symbol(kBytesWritten): 0,
1599:  Symbol(kNeedDrain): false,
1600:  Symbol(corked): 0,
1601:  Symbol(kChunkedBuffer): [],
1602:  Symbol(kChunkedLength): 0,
1603:  Symbol(kSocket): [Socket],
1604:  Symbol(kOutHeaders): [Object: null prototype],
1605:  Symbol(errored): null,
1606:  Symbol(kHighWaterMark): 65536,
...

1717:  upgradeOrConnect: false,
1718:  parser: null,
1719:  maxHeadersCount: null,
1720:  reusedSocket: false,
1721:  host: 'localhost',
1722:  protocol: 'http:',
1723:  Symbol(shapeMode): false,
1724:  Symbol(kCapture): false,
1725:  Symbol(kBytesWritten): 0,
1726:  Symbol(kNeedDrain): false,
1727:  Symbol(corked): 0,
1728:  Symbol(kChunkedBuffer): [],
1729:  Symbol(kChunkedLength): 0,
1730:  Symbol(kSocket): [Socket],
1731:  Symbol(kOutHeaders): [Object: null prototype],
1732:  Symbol(errored): null,
1733:  Symbol(kHighWaterMark): 65536,
...

1768:  Symbol(kCapture): false,
1769:  Symbol(kHeaders): [Object],
1770:  Symbol(kHeadersCount): 22,
1771:  Symbol(kTrailers): null,
1772:  Symbol(kTrailersCount): 0
1773:  },
1774:  _resBuffered: true,
1775:  response: [Circular *2],
1776:  called: true,
1777:  Symbol(shapeMode): false,
1778:  Symbol(kCapture): false
1779:  },
1780:  req: <ref *3> ClientRequest {
1781:  _events: [Object: null prototype] {
1782:  drain: [Function],
1783:  error: [Function (anonymous)],
1784:  finish: [Function: requestOnFinish]
...

1878:  upgradeOrConnect: false,
1879:  parser: null,
1880:  maxHeadersCount: null,
1881:  reusedSocket: false,
1882:  host: 'localhost',
1883:  protocol: 'http:',
1884:  Symbol(shapeMode): false,
1885:  Symbol(kCapture): false,
1886:  Symbol(kBytesWritten): 0,
1887:  Symbol(kNeedDrain): false,
1888:  Symbol(corked): 0,
1889:  Symbol(kChunkedBuffer): [],
1890:  Symbol(kChunkedLength): 0,
1891:  Symbol(kSocket): Socket {
1892:  connecting: false,
1893:  _hadError: false,
1894:  _parent: null,
1895:  _host: 'localhost',
1896:  _closeAfterHandlingError: false,
1897:  _events: [Object],
...

1918:  Symbol(shapeMode): true,
1919:  Symbol(kCapture): false,
1920:  Symbol(kSetNoDelay): true,
1921:  Symbol(kSetKeepAlive): false,
1922:  Symbol(kSetKeepAliveInitialDelay): 0,
1923:  Symbol(kSetTOS): undefined,
1924:  Symbol(kBytesRead): 0,
1925:  Symbol(kBytesWritten): 0
1926:  },
1927:  Symbol(kOutHeaders): [Object: null prototype] {
1928:  host: [Array],
1929:  'accept-encoding': [Array],
1930:  'content-type': [Array],
1931:  'content-length': [Array]
1932:  },
1933:  Symbol(errored): null,
1934:  Symbol(kHighWaterMark): 65536,
...

1959:  'x-ratelimit-limit': '999999',
1960:  'x-ratelimit-remaining': '999974',
1961:  date: 'Sun, 17 May 2026 12:07:15 GMT',
1962:  'x-ratelimit-reset': '1779019696',
1963:  'content-type': 'application/json; charset=utf-8',
1964:  'content-length': '62',
1965:  etag: 'W/"3e-c22+Nq37KkPTgt2Yh0qQIIkF+C0"',
1966:  connection: 'close'
1967:  },
1968:  statusCode: 200,
1969:  status: 200,
1970:  statusType: 2,
1971:  info: false,
1972:  ok: true,
1973:  redirect: false,
1974:  clientError: false,
1975:  serverError: false,
1976:  error: false,
1977:  created: false,
...

1998:  ✔ bad changeset
1999:  ✔ missing attrib in pool
2000:  ✔ extra attrib in pool
2001:  ✔ changeset refers to non-existent attrib
2002:  ✔ pad atext does not match
2003:  ✔ missing chat message
2004:  revisions are supported in txt and html export
2005:  �[32m[2026-05-17T12:07:15.668] [INFO] settings - �[39mExporting pad "c0Kf8" in txt format
2006:  �[32m[2026-05-17T12:07:15.671] [INFO] settings - �[39mExporting pad "c0Kf8" in txt format
2007:  ✔ txt request rev 1
2008:  �[32m[2026-05-17T12:07:15.675] [INFO] settings - �[39mExporting pad "c0Kf8" in txt format
2009:  ✔ txt request rev 2
2010:  �[32m[2026-05-17T12:07:15.678] [INFO] settings - �[39mExporting pad "c0Kf8" in txt format
2011:  ✔ txt request rev 1test returns rev 1
2012:  �[32m[2026-05-17T12:07:15.681] [INFO] settings - �[39mExporting pad "c0Kf8" in txt format
2013:  �[91m[2026-05-17T12:07:15.682] [ERROR] settings - �[39mapierror: rev is not a number
2014:  at checkValidRev (/home/runner/work/etherpad/etherpad/src/node/utils/checkValidRev.ts:14:11)
2015:  at Object.exports.doExport (/home/runner/work/etherpad/etherpad/src/node/handler/ExportHandler.ts:64:22)
2016:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
2017:  at async <anonymous> (/home/runner/work/etherpad/etherpad/src/node/hooks/express/importexport.ts:72:9)
2018:  9) txt request rev test1 is 403
2019:  �[32m[2026-05-17T12:07:15.688] [INFO] settings - �[39mExporting pad "c0Kf8" in txt format
2020:  ✔ txt request rev 5 returns head rev
2021:  �[32m[2026-05-17T12:07:15.692] [INFO] settings - �[39mExporting pad "c0Kf8" in html format
2022:  ✔ html request rev 1
2023:  �[32m[2026-05-17T12:07:15.696] [INFO] settings - �[39mExporting pad "c0Kf8" in html format
2024:  ✔ html request rev 2
2025:  �[32m[2026-05-17T12:07:15.700] [INFO] settings - �[39mExporting pad "c0Kf8" in html format
2026:  ✔ html request rev 1test returns rev 1
2027:  �[32m[2026-05-17T12:07:15.704] [INFO] settings - �[39mExporting pad "c0Kf8" in html format
2028:  �[91m[2026-05-17T12:07:15.705] [ERROR] settings - �[39mapierror: rev is not a number
2029:  at checkValidRev (/home/runner/work/etherpad/etherpad/src/node/utils/checkValidRev.ts:14:11)
2030:  at Object.exports.doExport (/home/runner/work/etherpad/etherpad/src/node/handler/ExportHandler.ts:64:22)
2031:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
2032:  at async <anonymous> (/home/runner/work/etherpad/etherpad/src/node/hooks/express/importexport.ts:72:9)
2033:  10) html request rev test1 results in 500 response
2034:  �[32m[2026-05-17T12:07:15.707] [INFO] settings - �[39mExporting pad "c0Kf8" in html format
2035:  ✔ html request rev 5 returns head rev
2036:  Import authorization checks
2037:  ✔ !authn !exist -> create
2038:  ✔ !authn exist -> replace
2039:  �[32m[2026-05-17T12:07:15.728] [INFO] http - �[39mFailed authentication from IP ANONYMOUS
2040:  ✔ authn anonymous !exist -> fail
2041:  �[32m[2026-05-17T12:07:15.732] [INFO] http - �[39mFailed authentication from IP ANONYMOUS
2042:  ✔ authn anonymous exist -> fail
2043:  �[32m[2026-05-17T12:07:15.737] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
2044:  ✔ authn user create !exist -> create
2045:  �[32m[2026-05-17T12:07:15.745] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
2046:  ✔ authn user modify !exist -> fail
2047:  �[32m[2026-05-17T12:07:15.747] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
2048:  ✔ authn user readonly !exist -> fail
2049:  �[32m[2026-05-17T12:07:15.751] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
2050:  ✔ authn user create exist -> replace
2051:  �[32m[2026-05-17T12:07:15.759] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
2052:  ✔ authn user modify exist -> replace
2053:  �[32m[2026-05-17T12:07:15.766] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
2054:  ✔ authn user readonly exist -> fail
2055:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/api/instance.ts
2056:  Connectivity for instance-level API tests
2057:  ✔ can connect
2058:  getStats
2059:  ✔ Gets the stats of a running instance (59ms)
2060:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/api/pad.ts
2061:  Sanity checks
2062:  ✔ errors with invalid oauth token
2063:  Tests
2064:  ✔ deletes a Pad that does not exist
2065:  ✔ creates a new Pad
2066:  ✔ gets revision count of Pad
2067:  ✔ gets saved revisions count of Pad
2068:  ✔ gets saved revision list of Pad
2069:  ✔ get the HTML of Pad
2070:  ✔ list all pads
2071:  ✔ deletes the Pad
2072:  ✔ list all pads again
2073:  ✔ get the HTML of a Pad -- Should return a failure
2074:  ✔ creates a new Pad with text
...

2091:  ✔ Sets text on a pad Id
2092:  ✔ Gets text on a pad Id
2093:  ✔ Sets text on a pad Id including an explicit newline
2094:  ✔ Gets text on a pad Id and doesn't have an excess newline
2095:  ✔ Gets when pad was last edited
2096:  ✔ Move a Pad to a different Pad ID
2097:  ✔ Gets text from new pad
2098:  ✔ Move pad back to original ID
2099:  ✔ Get text using original ID
2100:  ✔ Get last edit of original ID
2101:  ✔ Append text to a pad Id
2102:  ✔ getText of old revision
2103:  ✔ Sets the HTML of a Pad attempting to pass ugly HTML
2104:  12) Pad with complex nested lists of different types
2105:  ✔ Pad with white space between list items
2106:  ✔ errors if pad can be created
2107:  ✔ copies the content of a existent pad
2108:  ✔ does not add an useless revision
2109:  ✔ creates a new Pad with empty text
2110:  ✔ deletes with empty text
2111:  copyPadWithoutHistory
2112:  ✔ returns a successful response
2113:  13) creates a new pad with the same content as the source pad
2114:  ✔ copying to a non-existent group throws an error
2115:  ✔ source and destination attribute pools are independent (58ms)
2116:  copying to an existing pad
2117:  �[91m[2026-05-17T12:07:16.168] [ERROR] settings - �[39merroring out without force
2118:  ✔ force=false fails
2119:  ✔ force=true succeeds
2120:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/api/restoreRevision.ts
2121:  �[33m[2026-05-17T12:07:16.191] [WARN] settings - �[39mAuthorManager.getAuthor4Token() is deprecated; use AuthorManager.getAuthorId() instead 
2122:  at Object.exports.getAuthor4Token (/home/runner/work/etherpad/etherpad/src/node/db/AuthorManager.ts:175:12)
2123:  at Context.<anonymous> (/home/runner/work/etherpad/etherpad/src/tests/backend/specs/api/restoreRevision.ts:32:36)
2124:  v1.2.11
2125:  - content matches
2126:  ✔ authorId ignored
2127:  v1.3.0
2128:  ✔ change is attributed to given authorId
2129:  ✔ authorId can be omitted
2130:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/api/sessionsAndGroups.ts
2131:  API Versioning
2132:  ✔ errors if can not connect
2133:  API: Group creation and deletion
...

2197:  �[32m[2026-05-17T12:07:16.377] [INFO] access - �[39m[LEAVE] pad:testChatPad socket:Qa9iOLWNO8olHuICAAAD IP:ANONYMOUS authorID:a.X8624WcZNaeEIgtO
2198:  �[33m[2026-05-17T12:07:16.386] [WARN] message - �[39mclient sent author token via CLIENT_READY message; cookie migration will take effect on next HTTP response. See docs/superpowers/specs/2026-04-19-gdpr-pr3-anon-identity-design.md
2199:  �[32m[2026-05-17T12:07:16.388] [INFO] access - �[39m[CREATE] pad:testChatPad socket:oUbXHZTb8ZnumC1OAAAF IP:ANONYMOUS authorID:a.2AYM13Q1nQUwjxPh
2200:  ✔ pad
2201:  �[32m[2026-05-17T12:07:16.391] [INFO] access - �[39m[LEAVE] pad:testChatPad socket:oUbXHZTb8ZnumC1OAAAF IP:ANONYMOUS authorID:a.2AYM13Q1nQUwjxPh
2202:  �[33m[2026-05-17T12:07:16.400] [WARN] message - �[39mclient sent author token via CLIENT_READY message; cookie migration will take effect on next HTTP response. See docs/superpowers/specs/2026-04-19-gdpr-pr3-anon-identity-design.md
2203:  �[32m[2026-05-17T12:07:16.401] [INFO] access - �[39m[CREATE] pad:testChatPad socket:RqEKTutrVsY8xIkoAAAH IP:ANONYMOUS authorID:a.dKUF7CbvydP1XDBo
2204:  ✔ padId
2205:  �[32m[2026-05-17T12:07:16.405] [INFO] access - �[39m[LEAVE] pad:testChatPad socket:RqEKTutrVsY8xIkoAAAH IP:ANONYMOUS authorID:a.dKUF7CbvydP1XDBo
2206:  �[33m[2026-05-17T12:07:16.412] [WARN] message - �[39mclient sent author token via CLIENT_READY message; cookie migration will take effect on next HTTP response. See docs/superpowers/specs/2026-04-19-gdpr-pr3-anon-identity-design.md
2207:  �[32m[2026-05-17T12:07:16.414] [INFO] access - �[39m[CREATE] pad:testChatPad socket:6MX2XIR4sylpfsACAAAJ IP:ANONYMOUS authorID:a.eQhD8hZEgFPL2GpH
2208:  ✔ mutations propagate
2209:  �[32m[2026-05-17T12:07:16.419] [INFO] access - �[39m[LEAVE] pad:testChatPad socket:6MX2XIR4sylpfsACAAAJ IP:ANONYMOUS authorID:a.eQhD8hZEgFPL2GpH
2210:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/clientvar_rev_consistency.ts
2211:  �[33m[2026-05-17T12:07:16.437] [WARN] settings - �[39mbypassing socket.io authentication and authorization checks due to settings.loadTest
2212:  �[91m[2026-05-17T12:07:16.437] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
2213:  �[32m[2026-05-17T12:07:16.437] [INFO] access - �[39m[ENTER] pad:U2dosXJEG0 socket:Ib9vZr0AMLGe3sPUAAAL IP:ANONYMOUS authorID:a.kF0V4CIVYhWBgdOn
2214:  ✔ CLIENT_VARS rev matches initialAttributedText state at that exact rev
2215:  �[32m[2026-05-17T12:07:16.441] [INFO] access - �[39m[LEAVE] pad:U2dosXJEG0 socket:Ib9vZr0AMLGe3sPUAAAL IP:ANONYMOUS authorID:a.kF0V4CIVYhWBgdOn
2216:  �[33m[2026-05-17T12:07:16.464] [WARN] settings - �[39mbypassing socket.io authentication and authorization checks due to settings.loadTest
2217:  �[91m[2026-05-17T12:07:16.465] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
2218:  �[32m[2026-05-17T12:07:16.465] [INFO] access - �[39m[ENTER] pad:qsmhSo7Ca2 socket:c5_r_sN2Kif1FvSOAAAN IP:ANONYMOUS authorID:a.xeXtL3D4rLMo9fAI
...

2249:  textColorFromBackgroundColor — invariant
2250:  ✔ always picks whichever of black/white gives the higher contrast
2251:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/compactPad.ts
2252:  API.compactPad()
2253:  ✔ collapses all history when keepRevisions is omitted
2254:  ✔ keeps only the last N revisions when keepRevisions is a number
2255:  ✔ rejects negative keepRevisions
2256:  ✔ rejects non-numeric keepRevisions
2257:  ✔ rejects fractional keepRevisions
2258:  ✔ refuses to run when cleanup.enabled is false
2259:  HTTP API dispatch (1.3.1)
2260:  ✔ passes keepRevisions from query string into compactPad
2261:  ✔ collapses all history when keepRevisions is absent from URL
2262:  runCompactAll (bin/compactAllPads loop)
2263:  ✔ parses --keep / --dry-run / no args
2264:  �[91m[2026-05-17T12:07:17.939] [ERROR] settings - �[39m--keep expects a non-negative integer; got abc
2265:  �[91m[2026-05-17T12:07:17.939] [ERROR] settings - �[39m--keep expects a non-negative integer; got -1
2266:  ✔ rejects --keep with non-integer / negative / unknown args
2267:  ✔ compacts every pad and tallies before/after revisions
2268:  ✔ honours --keep N by passing it through to compactPad
2269:  ✔ --dry-run does not call compactPad
2270:  ✔ keeps going when one pad fails to compact
2271:  ✔ keeps going when one pad fails the pre-flight count
2272:  ✔ reports listAllPads failure without iterating
2273:  ✔ handles an empty instance
2274:  ✔ end-to-end against the real HTTP handler
2275:  runCompactStale (bin/compactStalePads loop)
2276:  ✔ parses --older-than / --keep / --dry-run
2277:  �[91m[2026-05-17T12:07:17.968] [ERROR] settings - �[39m--older-than is required
2278:  �[91m[2026-05-17T12:07:17.968] [ERROR] settings - �[39m--older-than is required
2279:  �[91m[2026-05-17T12:07:17.969] [ERROR] settings - �[39m--older-than expects a non-negative integer; got abc
2280:  �[91m[2026-05-17T12:07:17.969] [ERROR] settings - �[39m--older-than expects a non-negative integer; got -1
2281:  ✔ rejects missing / invalid --older-than and unknown args
2282:  ✔ only compacts pads older than the cutoff
2283:  ✔ honours --keep N for stale pads
2284:  ✔ --dry-run does not call compactPad on stale pads
2285:  ✔ keeps going when one stale pad fails to compact
2286:  ✔ counts a getLastEdited failure as a failure but keeps going
2287:  ✔ reports listAllPads failure without iterating
2288:  ✔ handles an empty instance
2289:  ✔ handles an instance where every pad is fresh
2290:  ✔ skips a pad that gets edited between selection and compaction
2291:  ✔ counts a getLastEdited recheck failure as a failure
2292:  ✔ --older-than 0 treats every pad as stale
...

2320:  ✔ text matches
2321:  ✔ alines match
2322:  ✔ attributes are sorted in canonical order
2323:  A single completely empty line break within an ol should reset count if OL is closed off..
2324:  ✔ text matches
2325:  ✔ alines match
2326:  ✔ attributes are sorted in canonical order
2327:  A single <p></p> should create a new line
2328:  ✔ text matches
2329:  ✔ alines match
2330:  ✔ attributes are sorted in canonical order
2331:  Tests if ols properly get line numbers when in a normal OL #2
2332:  ✔ text matches
2333:  ✔ alines match
2334:  ✔ attributes are sorted in canonical order
2335:  First item being an UL then subsequent being OL will fail
2336:  - text matches
...

2445:  ✔ alines match
2446:  ✔ attributes are sorted in canonical order
2447:  nbsp preserved across span boundary
2448:  ✔ text matches
2449:  ✔ alines match
2450:  ✔ attributes are sorted in canonical order
2451:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/ensureAuthorTokenCookie.ts
2452:  ✔ mints a fresh t.* token when the cookie is absent
2453:  ✔ reuses the cookie value and does not emit Set-Cookie when already set
2454:  ✔ sets Secure when the request is HTTPS
2455:  ✔ uses SameSite=None when embedded cross-site (Sec-Fetch-Site: cross-site)
2456:  ✔ ignores an invalid existing cookie and mints a fresh one
2457:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/export.ts
2458:  �[32m[2026-05-17T12:07:18.244] [INFO] settings - �[39mExporting pad "testExportPad" in doc format
2459:  �[32m[2026-05-17T12:07:18.256] [INFO] LibreOffice - �[39m[3009] Converting /tmp/etherpad_export_3706563063.html to odt in /tmp
2460:  �[91m[2026-05-17T12:07:18.257] [ERROR] LibreOffice - �[39m[3009] Conversion failed: Error: Command exited with code 1: /bin/false --headless --invisible --nologo --nolockcheck --writer --convert-to odt /tmp/etherpad_export_3706563063.html --outdir /tmp
2461:  at exports (/home/runner/work/etherpad/etherpad/src/node/utils/run_cmd.ts:124:48)
2462:  at doConvertTask (/home/runner/work/etherpad/etherpad/src/node/utils/LibreOffice.ts:38:13)
2463:  at /home/runner/work/etherpad/etherpad/node_modules/.pnpm/async@3.2.6/node_modules/async/dist/async.js:151:38
2464:  at /home/runner/work/etherpad/etherpad/node_modules/.pnpm/async@3.2.6/node_modules/async/dist/async.js:4017:13
2465:  at Object.process (/home/runner/work/etherpad/etherpad/node_modules/.pnpm/async@3.2.6/node_modules/async/dist/async.js:1680:21)
2466:  at /home/runner/work/etherpad/etherpad/node_modules/.pnpm/async@3.2.6/node_modules/async/dist/async.js:1532:23
2467:  at /home/runner/work/etherpad/etherpad/node_modules/.pnpm/async@3.2.6/node_modules/async/dist/async.js:74:45
2468:  �[91m[2026-05-17T12:07:18.258] [ERROR] settings - �[39mError: Command exited with code 1: /bin/false --headless --invisible --nologo --nolockcheck --writer --convert-to odt /tmp/etherpad_export_3706563063.html --outdir /tmp
2469:  at exports (/home/runner/work/etherpad/etherpad/src/node/utils/run_cmd.ts:124:48)
2470:  at doConvertTask (/home/runner/work/etherpad/etherpad/src/node/utils/LibreOffice.ts:38:13)
2471:  at /home/runner/work/etherpad/etherpad/node_modules/.pnpm/async@3.2.6/node_modules/async/dist/async.js:151:38
2472:  at /home/runner/work/etherpad/etherpad/node_modules/.pnpm/async@3.2.6/node_modules/async/dist/async.js:4017:13
2473:  at Object.process (/home/runner/work/etherpad/etherpad/node_modules/.pnpm/async@3.2.6/node_modules/async/dist/async.js:1680:21)
2474:  at /home/runner/work/etherpad/etherpad/node_modules/.pnpm/async@3.2.6/node_modules/async/dist/async.js:1532:23
2475:  at /home/runner/work/etherpad/etherpad/node_modules/.pnpm/async@3.2.6/node_modules/async/dist/async.js:74:45
2476:  ✔ returns 500 on export error
2477:  native DOCX export (#7538)
2478:  �[32m[2026-05-17T12:07:18.261] [INFO] settings - �[39mExporting pad "testExportPad" in docx format
2479:  ✔ returns a valid DOCX archive (PK zip signature) (208ms)
2480:  �[32m[2026-05-17T12:07:18.470] [INFO] settings - �[39mExporting pad "testExportPad" in docx format
2481:  ✔ sends the Word-processing-ml content-type
2482:  native PDF export (#7538)
2483:  �[32m[2026-05-17T12:07:18.485] [INFO] settings - �[39mExporting pad "testExportPad" in pdf format
2484:  ✔ returns a valid %PDF- document (102ms)
2485:  �[32m[2026-05-17T12:07:18.587] [INFO] settings - �[39mExporting pad "testExportPad" in pdf format
2486:  ✔ sends application/pdf content-type
2487:  odt without soffice (#7538)
2488:  �[91m[2026-05-17T12:07:18.596] [ERROR] settings - �[39mImpossible to export pad "testExportPad" in odt format. There is no converter configured
2489:  ✔ returns the "not enabled" message for odt
...

3043:  at new Promise (<anonymous>)
3044:  at callHookFnAsync (/home/runner/work/etherpad/etherpad/src/static/js/pluginfw/hooks.ts:236:16)
3045:  at <anonymous> (/home/runner/work/etherpad/etherpad/src/static/js/pluginfw/hooks.ts:351:54)
3046:  at Array.map (<anonymous>)
3047:  at Object.exports.aCallAll (/home/runner/work/etherpad/etherpad/src/static/js/pluginfw/hooks.ts:351:13)
3048:  at getHTMLFromAtext (/home/runner/work/etherpad/etherpad/src/node/utils/ExportHtml.ts:504:19)
3049:  at async Object.getPadHTML (/home/runner/work/etherpad/etherpad/src/node/utils/ExportHtml.ts:43:10)
3050:  at async Context.<anonymous> (/home/runner/work/etherpad/etherpad/src/tests/backend/specs/export_list.ts:128:18)
3051:  ✔ nested ordered list counters reset when closing levels
3052:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/favicon.ts
3053:  ✔ uses custom favicon if set (relative pathname)
3054:  ✔ uses custom favicon from url
3055:  ✔ uses custom favicon if set (absolute pathname)
3056:  ✔ falls back if custom favicon is missing
3057:  ✔ uses skin favicon if present
3058:  �[91m[2026-05-17T12:07:18.748] [ERROR] settings - �[39m(node:2805) [DEP0147] DeprecationWarning: In future versions of Node.js, fs.rmdir(path, { recursive: true }) will be removed. Use fs.rm(path, { recursive: true }) instead
3059:  (Use `node --trace-deprecation ...` to show where the warning was created)
...

3412:  ✔ defer call cb(unrejectedPromise) then defer call to cb(resolvedPromise) (diff. outcomes) -> log+throw
3413:  ✔ defer call cb(unrejectedPromise) then defer call to cb(rejectedPromise) (diff. outcomes) -> log+throw
3414:  ✔ defer call cb(unrejectedPromise) then defer call to cb(rejectedPromise) (same outcome) -> only log
3415:  ✔ defer call cb(unrejectedPromise) then defer call to cb(unresolvedPromise) (diff. outcomes) -> log+throw
3416:  ✔ defer call cb(unrejectedPromise) then defer call cb(unrejectedPromise) (diff. outcomes) -> log+throw
3417:  ✔ defer call cb(unrejectedPromise) then defer call cb(unrejectedPromise) (same outcome) -> only log
3418:  hooks.aCallAll
3419:  basic behavior
3420:  ✔ calls all asynchronously, returns values in order
3421:  ✔ passes hook name
3422:  ✔ undefined context -> {}
3423:  ✔ null context -> {}
3424:  ✔ context unmodified
3425:  aCallAll callback
3426:  ✔ exception in callback rejects
3427:  ✔ propagates error on exception
3428:  ✔ propagages null error on success
3429:  ✔ propagages results on success
...

3526:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/lowerCasePadIds.ts
3527:  not activated
3528:  ✔ do nothing
3529:  activated
3530:  ✔ lowercase pad ids
3531:  �[32m[2026-05-17T12:07:19.513] [INFO] access - �[39m[CREATE] pad:ALREADYexistingPad socket:OUV-ujl0r8LbGaz9AAAR IP:ANONYMOUS authorID:a.u8PVgOsQaY6yQBD4
3532:  �[32m[2026-05-17T12:07:19.528] [INFO] access - �[39m[CREATE] pad:alreadyexistingpad socket:wm0c3uUt2PyPLP5KAAAT IP:ANONYMOUS authorID:a.CGGY631umRWoANh4
3533:  ✔ keeps old pads accessible
3534:  �[32m[2026-05-17T12:07:19.532] [INFO] access - �[39m[LEAVE] pad:alreadyexistingpad socket:wm0c3uUt2PyPLP5KAAAT IP:ANONYMOUS authorID:a.CGGY631umRWoANh4
3535:  �[32m[2026-05-17T12:07:19.532] [INFO] access - �[39m[LEAVE] pad:ALREADYexistingPad socket:OUV-ujl0r8LbGaz9AAAR IP:ANONYMOUS authorID:a.u8PVgOsQaY6yQBD4
3536:  �[32m[2026-05-17T12:07:19.546] [INFO] access - �[39m[CREATE] pad:maliciousattempt socket:egaHd_uTjuaU2WPKAAAV IP:ANONYMOUS authorID:a.wQ9fkyz8uOpwMGwU
3537:  ✔ disallow creation of different case pad-name via socket connection
3538:  �[32m[2026-05-17T12:07:19.549] [INFO] access - �[39m[LEAVE] pad:maliciousattempt socket:egaHd_uTjuaU2WPKAAAV IP:ANONYMOUS authorID:a.wQ9fkyz8uOpwMGwU
3539:  /home/runner/work/etherpad/etherpad/src/tests/backend/specs/messages.ts
3540:  CHANGESET_REQ
3541:  �[91m[2026-05-17T12:07:19.563] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3542:  �[32m[2026-05-17T12:07:19.563] [INFO] access - �[39m[ENTER] pad:hc4RIoPPnH socket:J0qpfGE1nktnWUAYAAAX IP:ANONYMOUS authorID:a.kYHpwf1QPCsVVoC7
3543:  �[91m[2026-05-17T12:07:19.575] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3544:  �[32m[2026-05-17T12:07:19.575] [INFO] access - �[39m[ENTER] pad:hc4RIoPPnH socket:HibEMB6mqUDY14A_AAAZ IP:ANONYMOUS authorID:a.H6le5nfwyZ32ohzu
3545:  ✔ users are unable to read changesets from other pads
3546:  �[32m[2026-05-17T12:07:20.585] [INFO] access - �[39m[LEAVE] pad:hc4RIoPPnH socket:J0qpfGE1nktnWUAYAAAX IP:ANONYMOUS authorID:a.kYHpwf1QPCsVVoC7
3547:  �[32m[2026-05-17T12:07:20.585] [INFO] access - �[39m[LEAVE] pad:hc4RIoPPnH socket:HibEMB6mqUDY14A_AAAZ IP:ANONYMOUS authorID:a.H6le5nfwyZ32ohzu
3548:  �[91m[2026-05-17T12:07:20.599] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3549:  �[32m[2026-05-17T12:07:20.599] [INFO] access - �[39m[ENTER] pad:OkdcLI4GoL socket:_aPKFH63zuASYc4iAAAb IP:ANONYMOUS authorID:a.bFL5zI6ThskJb9bX
3550:  �[91m[2026-05-17T12:07:20.609] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3551:  �[32m[2026-05-17T12:07:20.609] [INFO] access - �[39m[ENTER] pad:OkdcLI4GoL socket:Gdyu4L6_Trl21vTWAAAd IP:ANONYMOUS authorID:a.7PxlZGfp94v4VxKs
3552:  �[91m[2026-05-17T12:07:21.613] [ERROR] socket.io - �[39mError handling pad message from Gdyu4L6_Trl21vTWAAAd: Error: CHANGESET_REQ: rev is not a number
3553:  at Object.exports.handleMessage (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:612:11)
3554:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
3555:  at async <anonymous> (/home/runner/work/etherpad/etherpad/src/node/handler/SocketIORouter.ts:85:14)
3556:  ✔ CHANGESET_REQ: verify revNum is a number (regression)
3557:  �[32m[2026-05-17T12:07:21.616] [INFO] access - �[39m[LEAVE] pad:OkdcLI4GoL socket:_aPKFH63zuASYc4iAAAb IP:ANONYMOUS authorID:a.bFL5zI6ThskJb9bX
3558:  �[32m[2026-05-17T12:07:21.616] [INFO] access - �[39m[LEAVE] pad:OkdcLI4GoL socket:Gdyu4L6_Trl21vTWAAAd IP:ANONYMOUS authorID:a.7PxlZGfp94v4VxKs
3559:  �[91m[2026-05-17T12:07:21.631] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3560:  �[32m[2026-05-17T12:07:21.631] [INFO] access - �[39m[ENTER] pad:11RS3PbD72 socket:uG_IItZpv_hpyvJOAAAf IP:ANONYMOUS authorID:a.bGYZtNCd4fKqRMMQ
3561:  �[91m[2026-05-17T12:07:21.644] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3562:  �[32m[2026-05-17T12:07:21.644] [INFO] access - �[39m[ENTER] pad:11RS3PbD72 socket:9ZqtvtQKzdCZANZCAAAh IP:ANONYMOUS authorID:a.wnlMEYMDrqeL5K2E
3563:  ✔ CHANGESET_REQ: revNum is converted to number if possible (regression)
3564:  �[32m[2026-05-17T12:07:22.650] [INFO] access - �[39m[LEAVE] pad:11RS3PbD72 socket:uG_IItZpv_hpyvJOAAAf IP:ANONYMOUS authorID:a.bGYZtNCd4fKqRMMQ
3565:  �[32m[2026-05-17T12:07:22.650] [INFO] access - �[39m[LEAVE] pad:11RS3PbD72 socket:9ZqtvtQKzdCZANZCAAAh IP:ANONYMOUS authorID:a.wnlMEYMDrqeL5K2E
3566:  �[91m[2026-05-17T12:07:22.665] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3567:  �[32m[2026-05-17T12:07:22.665] [INFO] access - �[39m[ENTER] pad:8VEAMwxaER socket:hrwpA_krhMEM87DVAAAj IP:ANONYMOUS authorID:a.bg1Ug15zG2bFWUip
3568:  �[91m[2026-05-17T12:07:22.678] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3569:  �[32m[2026-05-17T12:07:22.678] [INFO] access - �[39m[ENTER] pad:8VEAMwxaER socket:DdOdiGjA66BYWxgJAAAl IP:ANONYMOUS authorID:a.je0JJL1LNLf7osyn
3570:  ✔ CHANGESET_REQ: revNum 2 is converted to head rev 1 (regression)
3571:  �[32m[2026-05-17T12:07:23.685] [INFO] access - �[39m[LEAVE] pad:8VEAMwxaER socket:hrwpA_krhMEM87DVAAAj IP:ANONYMOUS authorID:a.bg1Ug15zG2bFWUip
3572:  �[32m[2026-05-17T12:07:23.686] [INFO] access - �[39m[LEAVE] pad:8VEAMwxaER socket:DdOdiGjA66BYWxgJAAAl IP:ANONYMOUS authorID:a.je0JJL1LNLf7osyn
3573:  USER_CHANGES
3574:  �[91m[2026-05-17T12:07:23.701] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3575:  �[32m[2026-05-17T12:07:23.701] [INFO] access - �[39m[ENTER] pad:Zb4in2FI8Z socket:ZeSRUsofkUgm3Z-HAAAn IP:ANONYMOUS authorID:a.OS5Yo2r0tLeXmU2Q
3576:  �[91m[2026-05-17T12:07:23.714] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3577:  �[32m[2026-05-17T12:07:23.714] [INFO] access - �[39m[ENTER] pad:Zb4in2FI8Z socket:boCFFzUVPyktdCfUAAAp IP:ANONYMOUS authorID:a.hlOGk54aa7U28wjI
3578:  ✔ changes are applied
3579:  �[32m[2026-05-17T12:07:24.720] [INFO] access - �[39m[LEAVE] pad:Zb4in2FI8Z socket:ZeSRUsofkUgm3Z-HAAAn IP:ANONYMOUS authorID:a.OS5Yo2r0tLeXmU2Q
3580:  �[32m[2026-05-17T12:07:24.721] [INFO] access - �[39m[LEAVE] pad:Zb4in2FI8Z socket:boCFFzUVPyktdCfUAAAp IP:ANONYMOUS authorID:a.hlOGk54aa7U28wjI
3581:  �[91m[2026-05-17T12:07:24.736] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3582:  �[32m[2026-05-17T12:07:24.736] [INFO] access - �[39m[ENTER] pad:HZX082lchj socket:1-EOZd5lBQYa5ZEnAAAr IP:ANONYMOUS authorID:a.VuGeh7XMdSxeWZj9
3583:  �[91m[2026-05-17T12:07:24.748] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3584:  �[32m[2026-05-17T12:07:24.748] [INFO] access - �[39m[ENTER] pad:HZX082lchj socket:9VxbaLtm-5YA7MAqAAAt IP:ANONYMOUS authorID:a.7WCbj4GzZOxTKteJ
3585:  �[33m[2026-05-17T12:07:25.751] [WARN] message - �[39mFailed to apply USER_CHANGES from author a.VuGeh7XMdSxeWZj9 (socket 1-EOZd5lBQYa5ZEnAAAr) on pad HZX082lchj: Error: Not a changeset: this is not a valid changeset
3586:  at error (/home/runner/work/etherpad/etherpad/src/static/js/Changeset.ts:64:13)
3587:  at unpack (/home/runner/work/etherpad/etherpad/src/static/js/Changeset.ts:363:44)
3588:  at checkRep (/home/runner/work/etherpad/etherpad/src/static/js/Changeset.ts:246:20)
3589:  at handleUserChanges (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:840:5)
3590:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
3591:  ✔ bad changeset is rejected
3592:  �[32m[2026-05-17T12:07:25.753] [INFO] access - �[39m[LEAVE] pad:HZX082lchj socket:1-EOZd5lBQYa5ZEnAAAr IP:ANONYMOUS authorID:a.VuGeh7XMdSxeWZj9
3593:  �[32m[2026-05-17T12:07:25.753] [INFO] access - �[39m[LEAVE] pad:HZX082lchj socket:9VxbaLtm-5YA7MAqAAAt IP:ANONYMOUS authorID:a.7WCbj4GzZOxTKteJ
3594:  �[91m[2026-05-17T12:07:25.768] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3595:  �[32m[2026-05-17T12:07:25.768] [INFO] access - �[39m[ENTER] pad:bNjz9VzmPt socket:eSMu6RfItfxo5BtGAAAv IP:ANONYMOUS authorID:a.qS7g7SIa7YBKLiD5
3596:  �[91m[2026-05-17T12:07:25.781] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3597:  �[32m[2026-05-17T12:07:25.781] [INFO] access - �[39m[ENTER] pad:bNjz9VzmPt socket:CeGJN0bjD8kTAEXAAAAx IP:ANONYMOUS authorID:a.RhNQrhGXHb12UwjO
3598:  �[33m[2026-05-17T12:07:26.784] [WARN] message - �[39mFailed to apply USER_CHANGES from author a.qS7g7SIa7YBKLiD5 (socket eSMu6RfItfxo5BtGAAAv) on pad bNjz9VzmPt: Error: Author a.qS7g7SIa7YBKLiD5 submitted an insert without an author attribute in changeset Z:1>5+5$hello
3599:  at handleUserChanges (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:887:15)
3600:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
3601:  ✔ insert without author attribute is rejected
3602:  �[32m[2026-05-17T12:07:26.786] [INFO] access - �[39m[LEAVE] pad:bNjz9VzmPt socket:eSMu6RfItfxo5BtGAAAv IP:ANONYMOUS authorID:a.qS7g7SIa7YBKLiD5
3603:  �[32m[2026-05-17T12:07:26.786] [INFO] access - �[39m[LEAVE] pad:bNjz9VzmPt socket:CeGJN0bjD8kTAEXAAAAx IP:ANONYMOUS authorID:a.RhNQrhGXHb12UwjO
3604:  �[91m[2026-05-17T12:07:26.801] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3605:  �[32m[2026-05-17T12:07:26.801] [INFO] access - �[39m[ENTER] pad:irrWk4FTjn socket:E8oRZFp_FruB1YchAAAz IP:ANONYMOUS authorID:a.G5vVdeZqueLgE0vN
3606:  �[91m[2026-05-17T12:07:26.813] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3607:  �[32m[2026-05-17T12:07:26.813] [INFO] access - �[39m[ENTER] pad:irrWk4FTjn socket:L8oC7XuMIh_iecwgAAA1 IP:ANONYMOUS authorID:a.xvveOHl7HTzdObRJ
3608:  �[33m[2026-05-17T12:07:27.816] [WARN] message - �[39mFailed to apply USER_CHANGES from author a.G5vVdeZqueLgE0vN (socket E8oRZFp_FruB1YchAAAz) on pad irrWk4FTjn: Error: Author a.G5vVdeZqueLgE0vN tried to submit changes as author a.etherpad-system in changeset Z:1>5*0+5$hello
3609:  at handleUserChanges (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:874:17)
3610:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
3611:  ✔ insert claiming the reserved system author is rejected
3612:  �[32m[2026-05-17T12:07:27.818] [INFO] access - �[39m[LEAVE] pad:irrWk4FTjn socket:E8oRZFp_FruB1YchAAAz IP:ANONYMOUS authorID:a.G5vVdeZqueLgE0vN
3613:  �[32m[2026-05-17T12:07:27.818] [INFO] access - �[39m[LEAVE] pad:irrWk4FTjn socket:L8oC7XuMIh_iecwgAAA1 IP:ANONYMOUS authorID:a.xvveOHl7HTzdObRJ
3614:  �[91m[2026-05-17T12:07:27.832] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3615:  �[32m[2026-05-17T12:07:27.832] [INFO] access - �[39m[ENTER] pad:evNFoEsVly socket:MmI86XAmOOeua67tAAA3 IP:ANONYMOUS authorID:a.6LlveEz4IUJLdcGF
3616:  �[91m[2026-05-17T12:07:27.844] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3617:  �[32m[2026-05-17T12:07:27.844] [INFO] access - �[39m[ENTER] pad:evNFoEsVly socket:fgQmW0IgVZ-ypqupAAA5 IP:ANONYMOUS authorID:a.hVTMQiOwHm7irYFh
3618:  �[33m[2026-05-17T12:07:28.850] [WARN] message - �[39mFailed to apply USER_CHANGES from author a.6LlveEz4IUJLdcGF (socket MmI86XAmOOeua67tAAA3) on pad evNFoEsVly: Error: Rejected USER_CHANGES whose application would leave the pad without a trailing '\n' (length 7). Every USER_CHANGES must preserve the "doc ends with \n" invariant.
3619:  at handleUserChanges (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:960:13)
3620:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
3621:  ✔ changeset that would strand the trailing \n is rejected
3622:  �[32m[2026-05-17T12:07:28.853] [INFO] access - �[39m[LEAVE] pad:evNFoEsVly socket:MmI86XAmOOeua67tAAA3 IP:ANONYMOUS authorID:a.6LlveEz4IUJLdcGF
3623:  �[32m[2026-05-17T12:07:28.853] [INFO] access - �[39m[LEAVE] pad:evNFoEsVly socket:fgQmW0IgVZ-ypqupAAA5 IP:ANONYMOUS authorID:a.hVTMQiOwHm7irYFh
3624:  �[91m[2026-05-17T12:07:28.882] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3625:  �[32m[2026-05-17T12:07:28.882] [INFO] access - �[39m[ENTER] pad:gLrfuyZoil socket:CJuvgFj7sqvUDNJwAAA7 IP:ANONYMOUS authorID:a.z2jvKesnB14ByuMN
3626:  �[91m[2026-05-17T12:07:28.915] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3627:  �[32m[2026-05-17T12:07:28.916] [INFO] access - �[39m[ENTER] pad:gLrfuyZoil socket:rtI49hKUrGYBBPYjAAA9 IP:ANONYMOUS authorID:a.TC4jfnmEDU1ih27Y
3628:  ✔ retransmission is accepted, has no effect
3629:  �[32m[2026-05-17T12:07:29.928] [INFO] access - �[39m[LEAVE] pad:gLrfuyZoil socket:CJuvgFj7sqvUDNJwAAA7 IP:ANONYMOUS authorID:a.z2jvKesnB14ByuMN
3630:  �[32m[2026-05-17T12:07:29.929] [INFO] access - �[39m[LEAVE] pad:gLrfuyZoil socket:rtI49hKUrGYBBPYjAAA9 IP:ANONYMOUS authorID:a.TC4jfnmEDU1ih27Y
3631:  �[91m[2026-05-17T12:07:29.943] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3632:  �[32m[2026-05-17T12:07:29.943] [INFO] access - �[39m[ENTER] pad:6H1Ha2hTlS socket:pdhMo9uUd5R5M4qVAAA_ IP:ANONYMOUS authorID:a.kWC4MJrlTXadl9d4
3633:  �[91m[2026-05-17T12:07:29.956] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3634:  �[32m[2026-05-17T12:07:29.956] [INFO] access - �[39m[ENTER] pad:6H1Ha2hTlS socket:tEilpvG8ALW1VrhuAABB IP:ANONYMOUS authorID:a.Ebrgd8ruxP7KapSL
3635:  ✔ identity changeset is accepted, has no effect
3636:  �[32m[2026-05-17T12:07:30.964] [INFO] access - �[39m[LEAVE] pad:6H1Ha2hTlS socket:pdhMo9uUd5R5M4qVAAA_ IP:ANONYMOUS authorID:a.kWC4MJrlTXadl9d4
3637:  �[32m[2026-05-17T12:07:30.964] [INFO] access - �[39m[LEAVE] pad:6H1Ha2hTlS socket:tEilpvG8ALW1VrhuAABB IP:ANONYMOUS authorID:a.Ebrgd8ruxP7KapSL
3638:  �[91m[2026-05-17T12:07:30.977] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3639:  �[32m[2026-05-17T12:07:30.977] [INFO] access - �[39m[ENTER] pad:t8yAhHCSq9 socket:Rwv2qfVkqz5FTCW3AABD IP:ANONYMOUS authorID:a.ltBMTBtih9hFZ2iJ
3640:  �[91m[2026-05-17T12:07:30.989] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3641:  �[32m[2026-05-17T12:07:30.989] [INFO] access - �[39m[ENTER] pad:t8yAhHCSq9 socket:uIySgtU0-6qnhMfYAABF IP:ANONYMOUS authorID:a.1nZ9nl32Uj11pHGx
3642:  ✔ non-identity changeset with no net change is accepted, has no effect
3643:  �[32m[2026-05-17T12:07:31.997] [INFO] access - �[39m[LEAVE] pad:t8yAhHCSq9 socket:Rwv2qfVkqz5FTCW3AABD IP:ANONYMOUS authorID:a.ltBMTBtih9hFZ2iJ
3644:  �[32m[2026-05-17T12:07:31.997] [INFO] access - �[39m[LEAVE] pad:t8yAhHCSq9 socket:uIySgtU0-6qnhMfYAABF IP:ANONYMOUS authorID:a.1nZ9nl32Uj11pHGx
3645:  �[91m[2026-05-17T12:07:32.011] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3646:  �[32m[2026-05-17T12:07:32.011] [INFO] access - �[39m[ENTER] pad:i6woEDG8b7 socket:LlyLcdnLP7jeaAQZAABH IP:ANONYMOUS authorID:a.1GBCoglUusIpDHty
3647:  �[91m[2026-05-17T12:07:32.022] [ERROR] message - �[39mThere is no author for authorId: a.etherpad-system. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802
3648:  �[32m[2026-05-17T12:07:32.022] [INFO] access - �[39m[ENTER] pad:i6woEDG8b7 socket:Sew-8YiGSopw5HDsAABJ IP:ANONYMOUS authorID:a.Xn1YwVCU810CwNuM
3649:  �[91m[2026-05-17T12:07:33.025] [ERROR] socket.io - �[39mError handling pad message from Sew-8YiGSopw5HDsAABJ: Error: COLLABROOM: write attempt on read-only pad
3650:  at Object.exports.handleMessage (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:612:11)
3651:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
3652:  at async <anonymous> (/home/runner/work/etherpad/etherpad/src/node/handler/SocketIORouter.ts:85:14)
3653:  �[91m[2026-05-17T12:07:33.028] [ERROR] socket.io - �[39mError handling pad message from Sew-8YiGSopw5HDsAABJ: Error: COLLABROOM: write attempt on read-only pad
3654:  at Object.exports.handleMessage (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:612:11)
...

3902:  �[32m[2026-05-17T12:07:33.964] [INFO] access - �[39m[CREATE] pad:pad socket:1x25WOCi5vcfpHEZAABj IP:ANONYMOUS authorID:a.RBtRl69oRVn3bFJu username:user
3903:  �[32m[2026-05-17T12:07:33.965] [INFO] access - �[39m[LEAVE] pad:pad socket:1x25WOCi5vcfpHEZAABj IP:ANONYMOUS authorID:a.RBtRl69oRVn3bFJu username:user
3904:  �[32m[2026-05-17T12:07:33.966] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
3905:  �[32m[2026-05-17T12:07:33.976] [INFO] access - �[39m[CREATE] pad:pad socket:sxPTMfSORmu9TLzSAABl IP:ANONYMOUS authorID:a.4htSHB6ij0yvhlwy username:user
3906:  ✔ authn user read-only /p/pad -> 200, ok
3907:  �[32m[2026-05-17T12:07:33.979] [INFO] access - �[39m[LEAVE] pad:pad socket:sxPTMfSORmu9TLzSAABl IP:ANONYMOUS authorID:a.4htSHB6ij0yvhlwy username:user
3908:  �[32m[2026-05-17T12:07:33.981] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
3909:  �[32m[2026-05-17T12:07:33.992] [INFO] access - �[39m[CREATE] pad:pad socket:5U2BbZUtbKCJqNZgAABn IP:ANONYMOUS authorID:a.7swKIuDVQabpr2hG username:user
3910:  ✔ authz user /p/pad -> 200, ok
3911:  �[32m[2026-05-17T12:07:33.995] [INFO] access - �[39m[LEAVE] pad:pad socket:5U2BbZUtbKCJqNZgAABn IP:ANONYMOUS authorID:a.7swKIuDVQabpr2hG username:user
3912:  �[32m[2026-05-17T12:07:33.996] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
3913:  �[32m[2026-05-17T12:07:34.008] [INFO] access - �[39m[CREATE] pad:päd socket:Qosm3WvZsaRuyK2MAABp IP:ANONYMOUS authorID:a.GajFKZ7P8QldSTtr username:user
3914:  ✔ supports pad names with characters that must be percent-encoded
3915:  �[32m[2026-05-17T12:07:34.011] [INFO] access - �[39m[LEAVE] pad:päd socket:Qosm3WvZsaRuyK2MAABp IP:ANONYMOUS authorID:a.GajFKZ7P8QldSTtr username:user
3916:  Abnormal access attempts
3917:  �[32m[2026-05-17T12:07:34.013] [INFO] http - �[39mFailed authentication from IP ANONYMOUS
3918:  �[33m[2026-05-17T12:07:34.020] [WARN] message - �[39mclient sent author token via CLIENT_READY message; cookie migration will take effect on next HTTP response. See docs/superpowers/specs/2026-04-19-gdpr-pr3-anon-identity-design.md
3919:  �[91m[2026-05-17T12:07:34.021] [ERROR] socket.io - �[39mError handling pad message from KTkUvzKhtbXkuV9DAABr: Error: access denied
3920:  at Object.exports.handleMessage (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:508:11)
3921:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
3922:  at async <anonymous> (/home/runner/work/etherpad/etherpad/src/node/handler/SocketIORouter.ts:85:14)
3923:  ✔ authn anonymous /p/pad -> 401, error
3924:  �[32m[2026-05-17T12:07:34.023] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
3925:  �[32m[2026-05-17T12:07:34.034] [INFO] access - �[39m[CREATE] pad:pad socket:r-Ixjz04JNA4rnFyAABt IP:ANONYMOUS authorID:a.rLxSPs4y3kF9fDPS username:user
3926:  �[32m[2026-05-17T12:07:34.035] [INFO] access - �[39m[LEAVE] pad:pad socket:r-Ixjz04JNA4rnFyAABt IP:ANONYMOUS authorID:a.rLxSPs4y3kF9fDPS username:user
3927:  �[32m[2026-05-17T12:07:34.036] [INFO] http - �[39mFailed authentication from IP ANONYMOUS
3928:  �[33m[2026-05-17T12:07:34.044] [WARN] message - �[39mclient sent author token via CLIENT_READY message; cookie migration will take effect on next HTTP response. See docs/superpowers/specs/2026-04-19-gdpr-pr3-anon-identity-design.md
3929:  �[91m[2026-05-17T12:07:34.044] [ERROR] socket.io - �[39mError handling pad message from qyg6uhxXan3wqxGxAABv: Error: access denied
3930:  at Object.exports.handleMessage (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:508:11)
3931:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
3932:  at async <anonymous> (/home/runner/work/etherpad/etherpad/src/node/handler/SocketIORouter.ts:85:14)
3933:  ✔ authn anonymous read-only /p/pad -> 401, error
3934:  �[33m[2026-05-17T12:07:34.052] [WARN] message - �[39mclient sent author token via CLIENT_READY message; cookie migration will take effect on next HTTP response. See docs/superpowers/specs/2026-04-19-gdpr-pr3-anon-identity-design.md
3935:  �[91m[2026-05-17T12:07:34.052] [ERROR] socket.io - �[39mError handling pad message from D9nSS1Bz1I9kXOw3AABx: Error: access denied
3936:  at Object.exports.handleMessage (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:508:11)
3937:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
3938:  at async <anonymous> (/home/runner/work/etherpad/etherpad/src/node/handler/SocketIORouter.ts:85:14)
3939:  ✔ authn !cookie -> error
3940:  �[32m[2026-05-17T12:07:34.054] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
3941:  �[91m[2026-05-17T12:07:34.064] [ERROR] socket.io - �[39mError handling pad message from t1apCU2NDFSHX4hjAABz: Error: access denied
3942:  at Object.exports.handleMessage (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:508:11)
3943:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
3944:  at async <anonymous> (/home/runner/work/etherpad/etherpad/src/node/handler/SocketIORouter.ts:85:14)
3945:  ✔ authorization bypass attempt -> error
3946:  Authorization levels via authorize hook
3947:  �[32m[2026-05-17T12:07:34.066] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
3948:  �[32m[2026-05-17T12:07:34.077] [INFO] access - �[39m[CREATE] pad:pad socket:MCjTOZ92_uy9hjkPAAB1 IP:ANONYMOUS authorID:a.DKLrnAiLg34fs6xZ username:user
3949:  ✔ level='create' -> can create
3950:  �[32m[2026-05-17T12:07:34.082] [INFO] access - �[39m[LEAVE] pad:pad socket:MCjTOZ92_uy9hjkPAAB1 IP:ANONYMOUS authorID:a.DKLrnAiLg34fs6xZ username:user
3951:  �[32m[2026-05-17T12:07:34.083] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
3952:  �[32m[2026-05-17T12:07:34.095] [INFO] access - �[39m[CREATE] pad:pad socket:yIT2uQoAo3e4kR0mAAB3 IP:ANONYMOUS authorID:a.SHB9bCsU099JZEYQ username:user
3953:  ✔ level=true -> can create
3954:  �[32m[2026-05-17T12:07:34.098] [INFO] access - �[39m[LEAVE] pad:pad socket:yIT2uQoAo3e4kR0mAAB3 IP:ANONYMOUS authorID:a.SHB9bCsU099JZEYQ username:user
3955:  �[32m[2026-05-17T12:07:34.100] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
3956:  �[32m[2026-05-17T12:07:34.111] [INFO] access - �[39m[CREATE] pad:pad socket:55SkcRNJUniw20wOAAB5 IP:ANONYMOUS authorID:a.Uvj1llziU2DyEsGs username:user
3957:  ✔ level='modify' -> can modify
3958:  �[32m[2026-05-17T12:07:34.113] [INFO] access - �[39m[LEAVE] pad:pad socket:55SkcRNJUniw20wOAAB5 IP:ANONYMOUS authorID:a.Uvj1llziU2DyEsGs username:user
3959:  �[32m[2026-05-17T12:07:34.114] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
3960:  �[91m[2026-05-17T12:07:34.124] [ERROR] socket.io - �[39mError handling pad message from EF-2vcCGEHszJeoeAAB7: Error: access denied
3961:  at Object.exports.handleMessage (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:508:11)
3962:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
3963:  at async <anonymous> (/home/runner/work/etherpad/etherpad/src/node/handler/SocketIORouter.ts:85:14)
3964:  ✔ level='create' settings.editOnly=true -> unable to create
3965:  �[32m[2026-05-17T12:07:34.126] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
3966:  �[91m[2026-05-17T12:07:34.136] [ERROR] socket.io - �[39mError handling pad message from qsmxLsJPjRCxGzWwAAB9: Error: access denied
3967:  at Object.exports.handleMessage (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:508:11)
3968:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
3969:  at async <anonymous> (/home/runner/work/etherpad/etherpad/src/node/handler/SocketIORouter.ts:85:14)
3970:  ✔ level='modify' settings.editOnly=false -> unable to create
3971:  �[32m[2026-05-17T12:07:34.137] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
3972:  �[91m[2026-05-17T12:07:34.147] [ERROR] socket.io - �[39mError handling pad message from KTYgqmPTFgD2_OHKAAB_: Error: access denied
3973:  at Object.exports.handleMessage (/home/runner/work/etherpad/etherpad/src/node/handler/PadMessageHandler.ts:508:11)
3974:  at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
3975:  at async <anonymous> (/home/runner/work/etherpad/etherpad/src/node/handler/SocketIORouter.ts:85:14)
3976:  ✔ level='readOnly' -> unable to create
3977:  �[32m[2026-05-17T12:07:34.149] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
3978:  �[32m[2026-05-17T12:07:34.159] [INFO] access - �[39m[CREATE] pad:pad socket:iOZywbRgR4s4-HD8AACB IP:ANONYMOUS authorID:a.eV1Kh0W965prqFhK username:user
3979:  ✔ level='readOnly' -> unable to modify
3980:  �[32m[2026-05-17T12:07:34.162] [INFO] access - �[39m[LEAVE] pad:pad socket:iOZywbRgR4s4-HD8AACB IP:ANONYMOUS authorID:a.eV1Kh0W965prqFhK username:user
3981:  Authorization levels via user settings
3982:  �[32m[2026-05-17T12:07:34.163] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
3983:  �[32m[2026-05-17T12:07:34.174] [INFO] access - �[39m[CREATE] pad:pad socket:OVW_V5iMB8eCTo9IAACD IP:ANONYMOUS authorID:a.pCMvmMrUP5rL3...

@JohnMcLear JohnMcLear self-assigned this May 17, 2026
…iscovery

Read the pnpm test script from src/package.json, hand mocha the
same arguments under --dry-run --list-files, and assert that a
representative spec from tests/backend/specs/api/ and
tests/backend/specs/admin/ appears in the discovered list.

Locks in the glob fix from this PR: if anyone re-narrows the
script back to the previous tests/backend/specs/**.ts pattern
(which only matches depth 1), this vitest fails with a clear
"glob missed ..." message instead of letting the affected specs
silently drop out of CI.

Verified the test FAILS when the script is reverted to the
broken glob.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JohnMcLear JohnMcLear merged commit dbd4662 into develop May 17, 2026
24 of 29 checks passed
@JohnMcLear JohnMcLear deleted the fix/backend-tests-glob branch May 17, 2026 12:20
JohnMcLear added a commit that referenced this pull request May 17, 2026
#7796)

* test(admin): skip anonymizeAuthorSocket suite when ep_hash_auth is installed

#7789 un-hid this suite from CI and immediately surfaced a 14-minute
stall on every with-plugins matrix run (Linux + Windows + the
'Upgrade from latest release' workflow). Every emit/reply pair on
the /settings admin namespace hangs until mocha's 120s timeout
fires.

Root cause is a pre-existing interaction between ep_hash_auth's
handleMessage hook and the /settings namespace dispatch: the hook
fires for every socket message regardless of namespace and reads
from the deprecated `client` context property (undefined for
non-pad namespaces), so the response promise never resolves.
Tracked separately in #7795.

Until that lands, gate the suite on require.resolve('ep_hash_auth').
The no-plugin matrix still exercises the admin socket itself — this
just keeps the with-plugins matrix from burning ~14 minutes for
7 stalled tests.

Verified locally:
- no ep_hash_auth in node_modules → 7 passing
- ep_hash_auth resolvable → 0 passing, 7 pending

Why require.resolve and not pluginDefs.plugins[...]: Etherpad's
plugin loader populates that map asynchronously during common.init.
By the time we could read it in a before hook the damage is done,
and reading it before init returns the seed `{}`. Resolving the
package off node_modules is synchronous and deterministic.

Refs #7795

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(test): probe at the application layer; restore settings safely on skip

Two Qodo follow-ups on this PR:

1) Replace the static `require.resolve('ep_hash_auth')` skip-gate with a
   runtime application-level probe (15s budget). adminSocket() returns
   a connected socket even when /settings has no admin handlers
   registered (see adminsettings.ts:25 — non-admin sockets exit early
   without binding listeners). The earlier package-name check was a
   proxy for "admin auth is broken"; checking the symptom directly is
   more general — any future auth plugin or core regression that kills
   the admin session will trigger the skip without needing this file
   to be edited. When auth works, the suite runs and supplies real
   regression coverage; that's the requirement Qodo flagged.

2) Guard after() with a setupCompleted flag. The skip-via-this.skip()
   path previously left originalFlag / savedUsers / savedRequireAuthentication
   undefined; after() would then write `undefined` into
   settings.gdprAuthorErasure.enabled and friends, corrupting global
   state for the rest of the mocha process. Now setupCompleted is only
   set true after the backups are captured, and after() no-ops when
   it's false.

Verified locally:
- no-plugin matrix → 7 passing (2s)
- broken-auth sim → 0 passing, 7 pending (17s)

Refs #7795

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant